/*****************************************************************************
 * Copyright (C) 2008, 2009 Bauke Conijn, Adriaan Tichler
 *
 * This is free software; you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 3 of the License, or (at your option) any later
 * version.
 *
 * This is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Public License for more details
 *
 * To obtain a copy of the GNU General Public License, please see
 * <http://www.gnu.org.licenses/>
 *****************************************************************************/

/****************************************
 * SETTINGS
 ****************************************/

Feature.create("Settings",new Error().lineNumber-21);
Settings.type = {none: 0, string: 1, integer: 2, enumeration: 3, object: 4, bool: 5, set: 6};

// Determine server
Settings.server = location.href.match(/^(.*?\w)\//)[1];
Settings.server_id = Settings.server.replace(/http:\/\/(\w+)\.imperion\.(\w+)/,"$2_$1");

// Get the value of this setting.
// Note that (for example)
// "var u = Settings.username;" and "var u = Settings.s.username.get();" have the same effect.
Settings.get=function() {
    return this.parent[this.name];
}

// Set the value of this setting.
// Note that (for example)
// "Settings.username = u;" and "Settings.s.username.set(u);" have the same effect.
Settings.set=function(value) {
   this.parent[this.name]=value;
}

// Retrieves the value from the GM persistent storage database aka about:config
// Settings are not automatically updated.
// Call this if the value might have changed and you want it's latest value.
Settings.read=function() {
    try {
        if (this.type==Settings.type.none) {
            return; // intentionally no warning.
        }
        var param = Settings.server_id+"."+this.fullname;
        var x = GM_getValue(param, this.def_val);
        switch (this.type) {
            case Settings.type.string:
            break;

            case Settings.type.integer:
            case Settings.type.enumeration:
            x=x-0;
            break;

            case Settings.type.set:
            case Settings.type.object:
            x=eval(x);
            break;

            case Settings.type.bool:
            x=x==true;
            break;
        }
        this.set(x);
    } catch (e) {
        if (this&&this.exception)
            this.exception("Settings.read("+this.name+")", e);
        else
            GM_log("FATAL:"+e);
    }
};

// Stores the value in the GM persistent storage database aka about:config
Settings.write=function() {
    try {
        var param=Settings.server_id+"."+this.fullname;
        switch (this.type) {
            case Settings.type.none:
            this.warning("This setting ("+this.fullname+") has no type and can't be stored!");
            break;

            case Settings.type.string:
            case Settings.type.integer:
            case Settings.type.enumeration:
            case Settings.type.bool:
            GM_setValue(param, this.get());
            break;

            case Settings.type.set:
            case Settings.type.object:
            GM_setValue(param, uneval(this.get()));
            break;
        }
    } catch (e) {
        if (this&&this.exception)
            this.exception("Settings.write("+this.name+")", e);
        else
            GM_log("FATAL:"+e);
    }
};

// Removed the value from the GM persistent storage database aka about:config
Settings.remove=function() {
    try {
        var param=Settings.server_id+"."+this.fullname;
        GM_deleteValue(param);
        this.set(this.def_val);
    } catch (e) {
        if (this&&this.exception)
            this.exception("Settings.remove("+this.name+")", e);
        else
            GM_log("FATAL:"+e);
    }
};

// Returns a jQuery object that can be used to modify this setting.
Settings.config=function() {
    try {
        var s = $.new("span"); // the setting config thing
        s.append(this.name.replace(/_/g," ").pad(22)+": ");
        var setting=this;
        
        // Create the input element.
        switch (this.type) {
        case Settings.type.none: {
            s.append(this.get());
            break;
        }

        case Settings.type.string:
        case Settings.type.integer: {
            var input = $.new("input");
            input.val(this.get());
            s.append(input);
            input.change(function (e) {
                    var val=e.target.value;
                    if (setting.type==Settings.type.integer) {
                        if (val=="") val = setting.def_val;
                        else val-=0;
                    }
                    input.attr({value: val});
                    setting.set(val);
                    setting.write();
                });
            break;
        }

        case Settings.type.enumeration: {
            var select=$.new("select");
            var j = this.get();
            for (var i in this.typedata) {
                option=$.new("option").attr({value: i}).html(this.typedata[i]);
                if (i==j) option.attr({selected: "selected"});
                select.append(option);
            }
            s.append(select);
            select.change(function (e) {
                    var val=e.target.value-0;
                    setting.set(val);
                    setting.write();
                });
            break;
        }
        
        case Settings.type.object: {
            // TODO: have some more info for this object in some special cases.
            s.append("(Object)");
            break;
        }
        
        case Settings.type.bool: {
            var u=$.new("u").html(""+this.get());
            s.append(u);
            s.css({cursor: "pointer", 
                   color: (this.get()?'green':'red')});
            s.click(function (e) {
                    setting.set(!setting.get());
                    setting.write();
                    s.replaceWith(setting.config());
                });
            break;
        }
        
        case Settings.type.set: {
            for (var i in this.typedata) {
                var u=$.new("u").html(this.typedata[i]);
                u.css({cursor: "pointer", 
                      color: (this.get()[i]?'green':'red')});
                u.attr("id",this.name+"."+i);
                u.click(function (e) {
                        setting.get()[e.target.id.match(/\.(\d+)/)[1]-0]^=true;
                        setting.write();
                        s.replaceWith(setting.config());
                    });
                s.append("[").append(u).append("]");
            }
            break;
        }
        }

        // Add tooltip with a description (if available)
        if (this.description) {
            s.attr({title: this.description});
            var h = this.description.match("\\(([-a-zA-Z0-9.,_ ]+)\\)$");
            if (h)
                s.append(" "+h[1]);
        }
        s.append("\n");

        return s;
    } catch (e) {
        Settings.debug(e);
    }
};

Settings.init=function(){
    // Add some settings
    Settings.setting("race",           0,          Settings.type.enumeration, ["Terrans","Titans","Xen"]);
    Settings.setting("time_format",    0,          Settings.type.enumeration, ['Euro (dd.mm.yy 24h)', 'US (mm/dd/yy 12h)', 'UK (dd/mm/yy 12h', 'ISO (yy/mm/dd 24h)']);
    Settings.setting("current_tab",    "Settings", Settings.type.string,      undefined, "The tab that's currently selected in the settings menu. ");
    Settings.setting("planet_names",   {},         Settings.type.object,      undefined, "The names of yout planets");
    
    /*if (location.href.match(/about:cache\?device=timeline&/)) {
        var params=location.href.split("&");
        Settings.special={};
        for (var i=1; i<params.length; i++) {
            var z=params[i].split("=");
            Settings.special[z[0]]=z[1];
            GM_log("Param:"+params[i]);
        }
    }*/
};
Settings.run=function() {
    // Determine current planet
    Settings.planet=$(".planet a.icon").attr("href").replace("/planet/buildings/","")-0;
    Settings.planet_names[Settings.planet]=$("#planetList").text();
    Settings.s.planet_names.write();
};

// Correctly init debug now that it's possible
Settings.setting("global_debug_level", 0, Settings.type.enumeration, Feature.debug_categories, "Which categories of messages should be sent to the console. (Listed in descending order of severity).");
Settings.init_debug();

// Settings init will always run
Settings.call('init', true);
$(function(){Settings.call('run',true);});
